With the Framer Motion library, we can render animations in our React app easily.
In this article, we’ll take a look at how to get started with Framer Motion.
useReducedMotion
We can use the useReducedMotion
hook to animate our elements based on the current device’s reduced motion setting.
For example, we can write:
import React, { useState } from "react";
import { motion, useReducedMotion } from "framer-motion";
export default function App() {
const shouldReduceMotion = useReducedMotion();
const closedX = shouldReduceMotion ? 0 : "-100%";
const [isOpen, setIsOpen] = useState(true);
return (
<>
<button onClick={() => setIsOpen(!isOpen)}>toggle</button>
<motion.div
animate={{
opacity: isOpen ? 1 : 0,
x: isOpen ? 0 : closedX
}}
style={{ backgroundColor: "red", width: 100, height: 100 }}
/>
</>
);
}
We call the useReduceMotion
hook to get the shouldReduceMotion
variable.
We can use that to check if reduced motion setting is enabled.
Then we can use that to position the div based on the shouldReduceMotion
value.
usePresence
The usePresence
hook lets us access information about whether an element is still present in the React tree.
If isPresent
is false
, then a component has been remove from the tree, but AnimatePresence
won’t remove it until safeToRemove
has been called.
For example, we can write:
import React, { useEffect, useState } from "react";
import { usePresence } from "framer-motion";
export const Component = () => {
const [isPresent, safeToRemove] = usePresence();
useEffect(() => {
console.log(isPresent);
!isPresent && setTimeout(safeToRemove, 1000);
}, [isPresent]);
return <div style={{ backgroundColor: "red", width: 100, height: 100 }} />;
};
export default function App() {
const [isOpen, setIsOpen] = useState(true);
return (
<div>
<button onClick={() => setIsOpen(!isOpen)}>toggle</button>
{isOpen && <Component />}
</div>
);
}
to watch the isPresent
value in the useEffect
callback.
Then we call safeToRemove
to remove the component when it’s unloaded.
useIsPresent
The useIsPresent
hook is similar to usePresence
except that it doesn’t return the safeToRemove
function.
For example, we can write:
import React, { useEffect, useState } from "react";
import { useIsPresent } from "framer-motion";
export const Component = () => {
const isPresent = useIsPresent();
useEffect(() => {
isPresent && console.log("is present");
}, [isPresent]);
return <div style={{ backgroundColor: "red", width: 100, height: 100 }} />;
};
export default function App() {
const [isOpen, setIsOpen] = useState(true);
return (
<div>
<button onClick={() => setIsOpen(!isOpen)}>toggle</button>
{isOpen && <Component />}
</div>
);
}
to log the isPresent
value.
useDragControls
We can use the useDragControls
hook to create drag controls.
The drag controls can be passed into the draggable component’s dragControls
prop.
It exposes a start
method that can start dragging from pointer events or other components.
For instance, we can write:
import { motion, useDragControls } from "framer-motion";
import React from "react";
export default function App() {
const dragControls = useDragControls();
function startDrag(event) {
dragControls.start(event, { snapToCursor: true });
}
return (
<>
<div onPointerDown={startDrag}>click me</div>
<motion.div
style={{ backgroundColor: "red", width: 100, height: 100 }}
drag="x"
dragControls={dragControls}
/>
</>
);
}
We create the dragControls
with the useDragControls
hook.
Then we pass that into the dragControls
prop.
The drag
prop is set to 'x'
so that we can drag horizontally.
We also created the startDrag
function to call dragControls.start
to start dragging.
We pass in the mouse event object into start
and set snapToCursor
to true
to move the div towards our mouse cursor when we click on ‘click me’.
Conclusion
We can use various hooks that come with Framer Motion to control our animation.